/**
 * Copyright 2011 Honeywell Federal Manufacturing & Technologies, LLC. This material was produced under U.S. Government
 * contract DE-ACO4-01AL66850, Honeywell Federal Manufacturing & Technologies, LLC, (FM&T) with the U. S. Department of
 * Energy for the operation of the Kansas City Plant . The U.S. Government has rights to use, reproduce, and distribute
 * this software.  NEITHER THE GOVERNMENT NOR Honeywell Federal Manufacturing & Technologies, LLC, MAKES ANY WARRANTY,
 * EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE.  If software is modified to produce
 * derivative works, such modified software should be clearly marked, so as not to confuse it with the version available
 * from FM&T.
 *
 * Additionally, this program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License Version 3 published by the Free Software Foundation. Accordingly, this program is distributed in
 * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this library.
 * If not, see http://www.gnu.org/licenses/.
 */
package org.braintrain.domain;

import org.braintrain.domain.types.ModuleNumbering;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;

import javax.persistence.*;
import java.util.*;

/**
 * Stores the information related to a Module.  Also, to allow editing while
 * a module is being referenced by non-Delta users, "delta" objects are used
 * to store the changes to be made.
 * 
 * @author John Ericksen
 *
 */

@Entity
@Table( name="braintrain_module" )
@AssociationOverrides({
    @AssociationOverride(name="header.value", joinColumns=@JoinColumn(name="header_resource_id")),
    @AssociationOverride(name="header.deltaValue", joinColumns=@JoinColumn(name="dheader_resource_id")),
    @AssociationOverride(name="footer.value", joinColumns=@JoinColumn(name="footer_resource_id")),
    @AssociationOverride(name="footer.deltaValue", joinColumns=@JoinColumn(name="dfooter_resource_id"))}
)
public class Module extends BrainTrainBase implements Comparable<Module>{
    
    private static final long serialVersionUID = 4116089512238406266L;
    
    private boolean active = false;
    private boolean retired = false;
    private boolean testAnswersExist = false;
    
    private boolean unrestrictedUserAccess = false;
    
    private DeltaString name = new DeltaString();

    private DeltaString description = new DeltaString();
    
    private Set<Navigation> mainPages = new TreeSet<Navigation>();
    private Set<Navigation> linkPages = new TreeSet<Navigation>();
    private SortedSet<EvaluationData> evaluations = new TreeSet<EvaluationData>();
    private List<AnswerLog> answerLog = new ArrayList<AnswerLog>();
    
    private DeltaResource header = new DeltaResource();
    
    private DeltaResource footer = new DeltaResource();
    
    private ModuleNumbering numbering = ModuleNumbering.None;
    private boolean skipFinishedChapters = false;
    private Set<User> users;


    
    @ManyToMany(mappedBy="moduleAccess", targetEntity=User.class, fetch=FetchType.LAZY)
    public Set<User> getUsers() {
        return users;
    }
    public void setUsers(Set<User> users) {
        this.users = users;
    }
    
    @Enumerated(EnumType.STRING)
    public ModuleNumbering getNumbering() {
        return numbering;
    }
    public void setNumbering(ModuleNumbering numbering) {
        this.numbering = numbering;
    }
    @Embedded
    public DeltaResource getHeader() {
        return header;
    }
    public void setHeader(DeltaResource header) {
        this.header = header;
    }
    @Transient
    public synchronized DeltaResource getNullSafeHeader(){
        if(header == null){
            header = new DeltaResource();
        }
        return header;
    }
    @Embedded
    public DeltaResource getFooter() {
        return footer;
    }
    public void setFooter(DeltaResource footer) {
        this.footer = footer;
    }
    @Transient
    public synchronized DeltaResource getNullSafeFooter(){
        if(footer == null){
            footer = new DeltaResource();
        }
        return footer;
    }
    @Embedded
    @AttributeOverrides({
       @AttributeOverride(name="value", column = @Column(name="name")),
       @AttributeOverride(name="deltaValue", column = @Column(name="deltaName"))
    })
    public DeltaString getName() {
        return name;
    }
    public void setName(DeltaString name) {
        this.name = name;
    }
    @Transient
    public synchronized DeltaString getNullSafeName(){
        if(name == null){
            name = new DeltaString();
        }
        return name;
    }

    @Embedded
    @AttributeOverrides({
       @AttributeOverride(name="value", column = @Column(name="description", length=4000)),
       @AttributeOverride(name="deltaValue", column = @Column(name="deltaDescription", length=4000) )
    })
    public DeltaString getDescription() {
        return description;
    }
    public void setDescription(DeltaString description) {
        this.description = description;
    }
    @Transient
    public synchronized DeltaString getNullSafeDescription(){
        if(description == null){
            description = new DeltaString();
        }
        return description;
    }
    public boolean isActive() {
        return active;
    }
    public void setActive(boolean active) {
        this.active = active;
    }
    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    @JoinColumn( name="module_id" )
    //@Where(clause="mainNavigation = true")
    public Set<Navigation> getMainPages() {
        return mainPages;
    }
    public void setMainPages(Set<Navigation> pages) {
        this.mainPages = pages;
    }
    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    @JoinColumn( name="module_id" )
    //@Where(clause="mainNavigation = false")
    public Set<Navigation> getLinkPages() {
        return linkPages;
    }
    public void setLinkPages(Set<Navigation> pages) {
        this.linkPages = pages;
    }
    public int compareTo(Module module) {
    	return this.getNullSafeName().compareTo(module.getNullSafeName());
    }
    
    
    public boolean isSkipFinishedChapters() {
        return skipFinishedChapters;
    }
    public void setSkipFinishedChapters(boolean skipFinishedChapters) {
        this.skipFinishedChapters = skipFinishedChapters;
    }
    
    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    @JoinColumn( name="module_id" )
    @Sort(type=SortType.NATURAL)
    public SortedSet<EvaluationData> getEvaluations() {
        return evaluations;
    }
    public void setEvaluations(SortedSet<EvaluationData> evaluations) {
        this.evaluations = evaluations;
    }
    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    @JoinColumn( name="module_id" )
    @OrderBy("submitDate")
    public List<AnswerLog> getAnswerLog() {
        return answerLog;
    }
    public void setAnswerLog(List<AnswerLog> answerLog) {
        this.answerLog = answerLog;
    }
    public boolean isRetired() {
        return retired;
    }
    public void setRetired(boolean retired) {
        this.retired = retired;
    }
    
    public boolean isTestAnswersExist() {
        return testAnswersExist;
    }
    public void setTestAnswersExist(boolean testAnswersExist) {
        this.testAnswersExist = testAnswersExist;
    }
    public boolean isUnrestrictedUserAccess() {
        return unrestrictedUserAccess;
    }
    public void setUnrestrictedUserAccess(boolean unrestrictedUserAccess) {
        this.unrestrictedUserAccess = unrestrictedUserAccess;
    }
}
